﻿Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Data
Imports System.Windows.Forms


Namespace Othello
    ''' <summary>
    ''' Summary description for SquareControl.
    ''' </summary>
    ''' 

    Public Class SquareControl
        Inherits System.Windows.Forms.UserControl
        ''' <summary> 
        ''' Required designer variable.
        ''' </summary>
        Private components As System.ComponentModel.Container = Nothing

        ' Default color values.
        Public Shared ReadOnly ActiveSquareBackColorDefault As Color = Color.FromArgb(0, 224, 0)
        Public Shared ReadOnly MoveIndicatorColorDefault As Color = Color.Red
        Public Shared ReadOnly NormalBackColorDefault As Color = Color.Green
        Public Shared ReadOnly ValidMoveBackColorDefault As Color = Color.FromArgb(0, 176, 0)

        ' Colors used in rendering the control.
        Public Shared ActiveSquareBackColor As Color = ActiveSquareBackColorDefault
        Public Shared MoveIndicatorColor As Color = MoveIndicatorColorDefault
        Public Shared NormalBackColor As Color = NormalBackColorDefault
        Public Shared ValidMoveBackColor As Color = ValidMoveBackColorDefault

        ' This represents the contents of the square, see the values defined
        ' in the Board class.
        Public Contents As Integer
        Public PreviewContents As Integer

        ' These are used to set highlighting.
        Public IsValid As Boolean = False
        Public IsActive As Boolean = False
        Public IsNew As Boolean = False

        ' Used for animation.
        Public Shared ReadOnly AnimationStart As Integer = 6
        Public Shared ReadOnly AnimationStop As Integer = -SquareControl.AnimationStart
        Public AnimationCounter As Integer = SquareControl.AnimationStop

        ' These reflect the position of the square on the board.
        Public ReadOnly Property Row() As Integer
            Get
                Return Me.m_row
            End Get
        End Property
        Public ReadOnly Property Col() As Integer
            Get
                Return Me.m_col
            End Get
        End Property

        ' These reflect the public row and column properties.
        Private m_row As Integer
        Private m_col As Integer

        ' Drawing tools.
        Private Shared pen As New Pen(Color.Black)
        Private Shared solidBrush As New SolidBrush(Color.Black)
        Private Shared path As New GraphicsPath()
        Private Shared gradientBrush As PathGradientBrush

        Public Sub New(ByVal row As Integer, ByVal col As Integer)
            ' This call is required by the Windows.Forms Form Designer.
            InitializeComponent()

            ' TODO: Add any initialization after the InitForm call

            Me.Contents = Board.Empty
            Me.m_row = row
            Me.m_col = col

            ' Prevent the control from receiving focus via the TAB key.
            Me.TabStop = False

            ' Set the background color.
            Me.BackColor = SquareControl.NormalBackColor

            ' Redraw the control on a resize.
            Me.ResizeRedraw = True

            ' Set double-buffering to prevent flicker when drawing the control.
            SetStyle(ControlStyles.UserPaint, True)
            SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            SetStyle(ControlStyles.DoubleBuffer, True)
        End Sub

        ''' <summary> 
        ''' Clean up any resources being used.
        ''' </summary>
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If components IsNot Nothing Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub

#Region "Component Designer generated code"
        ''' <summary> 
        ''' Required method for Designer support - do not modify 
        ''' the contents of this method with the code editor.
        ''' </summary>
        Private Sub InitializeComponent()
            ' 
            ' SquareControl
            ' 
            Me.Name = "SquareControl"
            Me.Size = New System.Drawing.Size(32, 32)
            AddHandler Me.Paint, New System.Windows.Forms.PaintEventHandler(AddressOf Me.SquareControl_Paint)

        End Sub
#End Region

        '
        ' Returns a lighter or darker version of the given color.
        '
        Private Shared Function AdjustBrightness(ByVal color__1 As Color, ByVal m As Double) As Color
            Dim r As Integer = CInt(Math.Truncate(Math.Max(0, Math.Min(255, Math.Round(CDbl(color__1.R) * m)))))
            Dim g As Integer = CInt(Math.Truncate(Math.Max(0, Math.Min(255, Math.Round(CDbl(color__1.G) * m)))))
            Dim b As Integer = CInt(Math.Truncate(Math.Max(0, Math.Min(255, Math.Round(CDbl(color__1.B) * m)))))

            Return Color.FromArgb(r, g, b)
        End Function
        ' ===================================================================
        ' Paint event handler.
        ' ===================================================================

        Private Sub SquareControl_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
            ' Clear the square, filling with the appropriate background color.
            Dim backColor As Color = SquareControl.NormalBackColor
            If Me.IsValid Then
                backColor = SquareControl.ValidMoveBackColor
            End If
            If Me.IsActive Then
                backColor = SquareControl.ActiveSquareBackColor
            End If

            e.Graphics.Clear(backColor)

            ' Set drawing options.
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias

            ' Draw the border.
            Dim topLeft As New Point(0, 0)
            Dim topRight As New Point(Me.Width - 1, 0)
            Dim bottomLeft As New Point(0, Me.Height - 1)
            Dim bottomRight As New Point(Me.Width - 1, Me.Height - 1)
            SquareControl.pen.Color = SquareControl.AdjustBrightness(backColor, 1.5)
            SquareControl.pen.Width = 1
            e.Graphics.DrawLine(SquareControl.pen, bottomLeft, topLeft)
            e.Graphics.DrawLine(SquareControl.pen, topLeft, topRight)
            SquareControl.pen.Color = SquareControl.AdjustBrightness(backColor, 0.6)
            e.Graphics.DrawLine(SquareControl.pen, bottomLeft, bottomRight)
            e.Graphics.DrawLine(SquareControl.pen, bottomRight, topRight)

            ' Draw the disc, if any.
            If Me.Contents <> Board.Empty OrElse Me.PreviewContents <> Board.Empty Then
                ' Get size and position parameters based on the control size and animation state.
                Dim size As Integer = CInt(Math.Truncate(Me.Width * (If(Me.AnimationCounter > SquareControl.AnimationStop, 0.85, 0.8))))
                Dim offset As Integer = CInt((Me.Width - size) \ 2)
                Dim thickness As Integer = CInt(Math.Truncate(size * 0.08))
                Dim width As Integer = size
                Dim height As Integer = Math.Max(thickness, CInt(Math.Truncate(Math.Round(size * Math.Abs(CDbl(Me.AnimationCounter) / SquareControl.AnimationStart)))))
                Dim left As Integer = offset
                Dim top As Integer = offset + CInt(Math.Truncate(Math.Round(CDbl(size - height) / 2.0)))

                ' Draw the shadow.
                SquareControl.solidBrush.Color = Color.FromArgb((If(Me.PreviewContents = Board.Empty, 48, 24)), Color.Black)
                If Me.AnimationCounter <= SquareControl.AnimationStop Then
                    e.Graphics.FillEllipse(SquareControl.solidBrush, left + thickness, top + thickness, width, height)
                Else
                    e.Graphics.FillEllipse(SquareControl.solidBrush, left + thickness, top + thickness, width, size - top + thickness)
                End If

                ' Draw the disc face, if not on edge.
                If Me.AnimationCounter <> 0 Then
                    If Me.PreviewContents = Board.Empty Then
                        If Me.Contents = Board.Black Then
                            SquareControl.solidBrush.Color = Color.Black

                            ' If the disc is being flipped, switch the color.
                            If Me.AnimationCounter > 0 Then
                                SquareControl.solidBrush.Color = SquareControl.AdjustBrightness(Color.White, 0.8)
                            End If
                        Else
                            SquareControl.solidBrush.Color = SquareControl.AdjustBrightness(Color.White, 0.8)

                            ' If the disc is being flipped, switch the color.
                            If Me.AnimationCounter > 0 Then
                                SquareControl.solidBrush.Color = Color.Black
                            End If
                        End If
                    Else
                        If Me.PreviewContents = Board.Black Then
                            SquareControl.solidBrush.Color = Color.FromArgb(96, Color.Black)
                        Else
                            SquareControl.solidBrush.Color = Color.FromArgb(96, SquareControl.AdjustBrightness(Color.White, 0.8))
                        End If
                    End If
                    e.Graphics.FillEllipse(SquareControl.solidBrush, left, top, width, height)

                    ' Highlight the disc face.
                    SquareControl.path.Reset()
                    SquareControl.path.AddEllipse(left, top, width, height)
                    SquareControl.gradientBrush = New PathGradientBrush(SquareControl.path)
                    SquareControl.gradientBrush.CenterPoint = New Point(CInt(width \ 3), CInt(height \ 3))
                    If Me.PreviewContents = Board.Empty Then
                        If SquareControl.solidBrush.Color = Color.Black Then
                            SquareControl.gradientBrush.CenterColor = Color.FromArgb(128, Color.DarkGray)
                        Else
                            SquareControl.gradientBrush.CenterColor = Color.White
                        End If
                    Else
                        If Me.PreviewContents = Board.Black Then
                            SquareControl.gradientBrush.CenterColor = Color.FromArgb(48, Color.DarkGray)
                        Else
                            SquareControl.gradientBrush.CenterColor = Color.FromArgb(96, Color.White)
                        End If
                    End If
                    SquareControl.gradientBrush.SurroundColors = New Color() {SquareControl.solidBrush.Color}
                    e.Graphics.FillEllipse(SquareControl.gradientBrush, left, top, width, height)
                    SquareControl.gradientBrush.Dispose()

                    ' Draw a circle around the disc if it has been newly added.
                    If Me.IsNew Then
                        SquareControl.pen.Color = SquareControl.MoveIndicatorColor
                        SquareControl.pen.Width = 2
                        e.Graphics.DrawEllipse(SquareControl.pen, left, top, width, height)
                    End If
                End If
            End If
        End Sub

    End Class
End Namespace
